const isValidUTF8 = require('utf-8-validate');

class WebSocketConnect {
    static connections = new Map()

    /**
     * 广播
     * @param {object} data 数据
     * @param {array} filter 过滤
     */
    static sendAll(data, filter = []) {
        for (let connection of this.connections.values()) {
            if (filter.includes(connection.uid)) continue
            connection.send(data)
        }
    }
    /**
     * 发送指定用户
     * @param {object} data 数据
     * @param {string} uid 用户id
     */
    static sendTo(data, uid) {
        if (this.connections.has(uid)) {
            this.connections.get(uid).send(data)
        }
    }

}

//统一返回结果工具
class resultUtil {
    static ResultEntity(event, msg, data, merge = {}) {
        return {
            event,
            msg,
            data,
            ...merge
        }
    }
    static success(data = {}, msg = "成功", event = 'success') {
        return (this.ResultEntity(event, msg, data))
    }
    static error(msg = "错误", event = 'error', data = {}) {
        return (this.ResultEntity(event, msg, data))
    }
    static base(event, msg, data, merge = {}) {
        return (this.ResultEntity(event, msg, data, merge))
    }
    static responseOk(requestId = null, event, data = {}, msg = "ok", merge = {}) {
        merge.requestId = requestId
        return (this.ResultEntity(event, msg, data, merge))
    }
    static responseErr(requestId = null, event, msg = "error", merge = {}) {
        merge.requestId = requestId
        return (this.ResultEntity(event, msg, null, merge))
    }
    static responseReply(requestId = null, msg = "ok", data = {}, merge = {}) {
        merge.requestId = requestId
        return (this.ResultEntity('reply', msg, data, merge))
    }
}

class BaseSocket {
    constructor(ws, request, uid, route) {
        this.ws = ws
        this.request = request
        this.uid = uid
        this.route = route
        this.isAlive = true
        this.routeFun = (() => { })
    }
    /**
     * ping请求
     */
    ping() {
        this.ws.ping()
    }
    /**
     * 心跳
     */
    heartbeat() {
        this.isAlive = true;
    }
    ok(msg = "成功") {
        this.send(resultUtil.success(null, msg))
    }
    success(data, msg = '成功') {
        this.send(resultUtil.success(data, msg))
    }
    error(msg = "失败", event = 'error') {
        this.send(resultUtil.error(msg, event))
    }

    json(event, msg, data, args = {}) {
        this.send(resultUtil.base(event, msg, data, ...args))
    }

    outprintError(msg = "失败", event = 'close') {
        this.send(resultUtil.error(msg, event))
        this.close()
    }

    send(data) {
        try {
            if (typeof data == 'object') {
                return this.ws.send(JSON.stringify(data))
            }
            return this.ws.send(data)
        } catch (error) {
            console.table([error, data]);
        }
    }
    onError(err) {
        console.error(err)
        this.onHook('onError', arguments)
    }
    onClose() {
        WebSocketConnect.connections.delete(this.uid)
        console.log("onClose当前连接:" + WebSocketConnect.connections.size);

        this.onHook('onClose', arguments)
    }
    onOpen() {
        if (WebSocketConnect.connections.has(this.uid)) {
            WebSocketConnect.connections.get(this.uid).outprintError("异地登录")
            WebSocketConnect.connections.delete(this.uid)
        }
        WebSocketConnect.connections.set(this.uid, this)
        console.log("onOpen当前连接:" + WebSocketConnect.connections.size);

        this.onHook('onOpen', arguments)
    }
    onMessage() {
        this.isAlive = true
        let args = [...arguments]
        if (args.length > 0 && args[0] instanceof Buffer && isValidUTF8(args[0])) {
            args[0] = args[0].toString('utf-8')
            if (args[0] == 'heartbeat') {
                return
            }
        }
        this.onHook('onMessage', args)
    }
    onHook(key, args) {
        if (typeof this.routeFun.prototype[key] == 'function') {
            this.routeFun.prototype[key].apply(this, [...args])
        }
    }
    heartbeatClose() {
        this.error("长时间未回复已断开")
        this.close()
    }
    close() {
        console.log('断开连接');
        this.ws.terminate()
    }
}

module.exports = {
    WebSocketConnect,
    resultUtil,
    BaseSocket
}